package com.cema.manage.project.manage.antiCheat.service;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.cema.manage.common.exception.RiskException;
import com.cema.manage.common.utils.IpUtils;
import com.cema.manage.framework.shiro.web.session.OnlineWebSessionManager;
import com.cema.manage.project.enums.CallbackAdRecordEnum;
import com.cema.manage.project.enums.RedisEnum;
import com.cema.manage.project.enums.RiskEnum;
import com.cema.manage.project.manage.adRecord.domain.AdRecord;
import com.cema.manage.project.manage.adRecord.service.IAdRecordService;
import com.cema.manage.project.manage.adRecordSecondary.domain.AdRecordSecondary;
import com.cema.manage.project.manage.adRecordSecondary.service.IAdRecordSecondaryService;
import com.cema.manage.project.manage.antiCheat.domain.AntiCheat;
import com.cema.manage.project.manage.antiCheat.mapper.AntiCheatMapper;
import com.cema.manage.project.manage.userDailyActivity.domain.UserDailyActivity;
import com.cema.manage.project.manage.userDailyActivity.service.IUserDailyActivityService;
import com.cema.manage.project.util.DateUtils;
import com.cema.manage.redis.RedisService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 反作弊 服务层实现
 *
 * @author reasahi
 * @date 2024-07-15
 */
@Service
public class AntiCheatServiceImpl extends ServiceImpl<AntiCheatMapper, AntiCheat> implements IAntiCheatService {
    private static final Logger log = LoggerFactory.getLogger(AntiCheatServiceImpl.class);

    @Resource
    private RedisService redisService;

    @Resource
    private IAdRecordService adRecordService;

    @Resource
    private IUserDailyActivityService userDailyActivityService;

    @Resource
    private IAdRecordSecondaryService iAdRecordSecondaryService;

    /**
     * 今日广告总金币允许N金币
     *
     * @param usId
     * @return
     */
    @Override
    public String checkRiskAdvertisingCoins(Integer usId) {
        String riskValue = (String) redisService.get(RedisEnum.RISK_ADVERTISING_COINS.getKey());
        if (StrUtil.isEmpty(riskValue)) {
            return RiskEnum.RISK_NO.getValue();
        }
        List<AdRecord> recordList = getAdRecords(usId);
        if (ObjectUtil.isNull(recordList)) {
            return RiskEnum.RISK_NO.getValue();
        }
        int realityMoney = recordList.stream().mapToInt(AdRecord::getArRealityMoney).sum();
        if (realityMoney <= Integer.parseInt(riskValue)) {
            return RiskEnum.RISK_NO.getValue();
        }
        return RiskEnum.RISK_YES.getValue();
    }

    @Override
    public String checkRiskAdvertisingCoinsThanEqual(Integer usId) {
        String riskValue = (String) redisService.get(RedisEnum.RISK_ADVERTISING_COINS_THAN_EQUAL.getKey());
        if (StrUtil.isEmpty(riskValue)) {
            return RiskEnum.RISK_NO.getValue();
        }
        List<AdRecord> recordList = getAdRecords(usId);
        if (ObjectUtil.isNull(recordList)) {
            return RiskEnum.RISK_NO.getValue();
        }
        String[] strings = riskValue.split(",");
        int number = Integer.parseInt(strings[0]);
        if (recordList.size() < number) {
            return RiskEnum.RISK_NO.getValue();
        }
        int sum = 0;
        for (int i = 0; i < number; i++) {
            AdRecord record = recordList.get(i);
            sum = sum + record.getArRealityMoney();
        }
        int coins = Integer.parseInt(strings[1]);
        if (sum / number > coins) {
            return RiskEnum.RISK_NO.getValue();
        }
        return RiskEnum.RISK_YES.getValue();
    }

    @Override
    public String checkRiskAdvertisingCoinsThanEqualTwo(Integer usId) {
        String riskValue = (String) redisService.get(RedisEnum.RISK_ADVERTISING_COINS_THAN_EQUAL_TWO.getKey());
        CheckRiskAdvertising checkRiskAdvertising = new CheckRiskAdvertising(usId, riskValue).invoke();
        if (checkRiskAdvertising.is()) {
            return RiskEnum.RISK_NO.getValue();
        }
        String[] strings = checkRiskAdvertising.getStrings();
        int number = checkRiskAdvertising.getNumber();
        int sum = checkRiskAdvertising.getSum();
        int coins = checkRiskAdvertising.getCoins();
        int coinsTwo = Integer.parseInt(strings[2]);
        String risk = RiskEnum.RISK_YES.getValue();
        if (!(sum / number > coins && sum / number <= coinsTwo)) {
            risk = RiskEnum.RISK_NO.getValue();
        }
        log.info("用户ID:" + usId + "权限标识:" + risk + "执行策略：" + riskValue + "副广总价值:" + sum);
        return risk;
    }

    @Override
    public String checkRiskWhiteList(Integer usId) {
        String riskValue = (String) redisService.get(RedisEnum.RISK_WHITE_LIST.getKey());
        if (StrUtil.isEmpty(riskValue)) {
            return RiskEnum.RISK_NO.getValue();
        }
        boolean contains = riskValue.contains(String.valueOf(usId));
        if (!contains) {
            return RiskEnum.RISK_NO.getValue();
        }
        return RiskEnum.RISK_YES.getValue();
    }

    @Override
    public boolean checkRiskIpLoginNumber(Integer usId, String ip) {
        String riskValue = (String) redisService.get(RedisEnum.RISK_IP_LOGIN_NUMBER.getKey());
        if (StrUtil.isEmpty(riskValue)) {
            return false;
        }
        EntityWrapper<UserDailyActivity> entityWrapper = new EntityWrapper<>();
        entityWrapper.eq("uda_ip", ip);
        DateUtils.getCurrentDayTime(entityWrapper, "create_time");
        List<UserDailyActivity> userDailyActivityList = userDailyActivityService.selectList(entityWrapper);
        int count = 0;
        if (ObjectUtil.isNotNull(userDailyActivityList)) {
            userDailyActivityList = userDailyActivityList.stream().filter(userDailyActivity -> !usId.equals(userDailyActivity.getUsId())).collect(Collectors.toList());
            count = userDailyActivityList.size();
        }
        if (count < Integer.parseInt(riskValue)) {
            return false;
        }
        return true;
    }

    @Override
    public void checkIp(Integer usId, String ip) throws UnknownHostException {
        EntityWrapper<UserDailyActivity> entityWrapper = new EntityWrapper<>();
        DateUtils.getCurrentDayTime(entityWrapper, "create_time");
        entityWrapper.orderBy("login_time");
        List<UserDailyActivity> userDailyActivityList = userDailyActivityService.selectList(entityWrapper);
        if (ObjectUtil.isNull(userDailyActivityList) && userDailyActivityList.size() == 0) {
            return;
        }
        List<UserDailyActivity> userIpDailyActivityList = userDailyActivityList.stream().filter(userDailyActivity -> ip.equals(userDailyActivity.getUdaIp())).collect(Collectors.toList());
        if (ObjectUtil.isNotNull(userIpDailyActivityList) && userIpDailyActivityList.size() > 0) {
            String riskValueLogin = (String) redisService.get(RedisEnum.RISK_IP_LOGIN_NUMBER.getKey());
            if (StrUtil.isNotEmpty(riskValueLogin) && userIpDailyActivityList.size() > Integer.parseInt(riskValueLogin)) {
                userIpDailyActivityList = userIpDailyActivityList.subList(0, Integer.parseInt(riskValueLogin));
                userIpDailyActivityList = userIpDailyActivityList.stream().filter(userDailyActivity -> !usId.equals(userDailyActivity.getUsId())).collect(Collectors.toList());
                if (userIpDailyActivityList.size() == Integer.parseInt(riskValueLogin)) {
                    throw new RiskException("【同一个IP允许访问次数上限，请更换IP】如有疑问请微信扫码进群联系管理员：");
                }
            }
        }
        long sameNetwork = IpUtils.getInSameNetwork(ip);
        List<UserDailyActivity> sameNetworkDailyActivityList = userDailyActivityList.stream().filter(userDailyActivity -> String.valueOf(sameNetwork).equals(userDailyActivity.getUdaIpSameNetwork())).collect(Collectors.toList());
        if (ObjectUtil.isNotNull(sameNetworkDailyActivityList) && sameNetworkDailyActivityList.size() > 0) {
            String riskValue = (String) redisService.get(RedisEnum.RISK_IP_SAME_NETWORK.getKey());
            if (StrUtil.isNotEmpty(riskValue) && sameNetworkDailyActivityList.size() > Integer.parseInt(riskValue)) {
                sameNetworkDailyActivityList = sameNetworkDailyActivityList.subList(0, Integer.parseInt(riskValue));
                sameNetworkDailyActivityList = sameNetworkDailyActivityList.stream().filter(userDailyActivity -> !usId.equals(userDailyActivity.getUsId())).collect(Collectors.toList());
                if (sameNetworkDailyActivityList.size() == Integer.parseInt(riskValue)) {
                    throw new RiskException("【同一个网段IP允许访问次数上限，请更换网段】如有疑问请微信扫码进群联系管理员：");
                }
            }
        }
    }

    private List<AdRecord> getAdRecords(Integer usId) {
        EntityWrapper<AdRecord> recordEntityWrapper = new EntityWrapper<>();
        DateUtils.getCurrentDayTime(recordEntityWrapper, "create_time");
        recordEntityWrapper.eq("us_id", usId);
        recordEntityWrapper.eq("ar_callback", CallbackAdRecordEnum.CALLBACK_YES.getValue());
        return adRecordService.selectList(recordEntityWrapper);
    }

    private List<AdRecordSecondary> getAdRecordSecondary(Integer usId) {
        EntityWrapper<AdRecordSecondary> recordEntityWrapper = new EntityWrapper<>();
        DateUtils.getCurrentDayTime(recordEntityWrapper, "create_time");
        recordEntityWrapper.eq("us_id", usId);
        return iAdRecordSecondaryService.selectList(recordEntityWrapper);
    }


    private class CheckRiskAdvertising {
        private boolean myResult;
        private Integer usId;
        private String riskValue;
        private String[] strings;
        private int number;
        private int sum;
        private int coins;

        public CheckRiskAdvertising(Integer usId, String riskValue) {
            this.usId = usId;
            this.riskValue = riskValue;
        }

        boolean is() {
            return myResult;
        }

        public String[] getStrings() {
            return strings;
        }

        public int getNumber() {
            return number;
        }

        public int getSum() {
            return sum;
        }

        public int getCoins() {
            return coins;
        }

        public CheckRiskAdvertising invoke() {
            if (StrUtil.isEmpty(riskValue)) {
                myResult = true;
                return this;
            }
            List<AdRecord> recordList = getAdRecords(usId);
            if (ObjectUtil.isNull(recordList)) {
                myResult = true;
                return this;
            }
            strings = riskValue.split(",");
            number = Integer.parseInt(strings[0]);
            if (recordList.size() < number) {
                myResult = true;
                return this;
            }
            sum = 0;
            for (int i = 0; i < number; i++) {
                AdRecord record = recordList.get(i);
                sum = sum + record.getArRealityMoney();
                log.info(JSONUtil.toJsonStr(recordList));
                log.info(String.valueOf(recordList.size()));
                log.info(String.valueOf(sum));
            }
            //Banner
            List<AdRecordSecondary> adRecordSecondaryList = getAdRecordSecondary(usId);
            if (ObjectUtil.isNotNull(adRecordSecondaryList) && adRecordSecondaryList.size() > 0) {
                sum = sum + adRecordSecondaryList.stream().mapToInt(AdRecordSecondary::getArsRealityMoney).sum();
            }
            coins = Integer.parseInt(strings[1]);
            myResult = false;
            return this;
        }
    }
}
